Seznamy a řetězce

Pro práci například s větším počtem proměnných můžeme v Imagine použít tzv. seznamy, což je skupina dat uzavřená v hranatých závorkách, přičemž jednotlivé položky jsou oddělené mezerou. (Něco podobného jako v jiných programovacích jazycích pole proměnných.) Prvky seznamu mohou být znaky, slova, čísla, souřadnice, obrázky, nebo třeba také zase seznamy. Prázdný seznam jsou prázdné závorky: []. Podobně jako se seznamy je možné pracovat také se slovy, neboli řetězci, prostě posloupnostmi znaků.

Pro práci se seznamy a řetězci lze v Imagine použít například následující příkazy:
count - zjistí délku (počet prvků) seznamu, například: print count :cisla vytiskne počet prvků seznamu :cisla
item - vybere prvek seznamu, například: print item 3 :cisla vytiskne třetí prvek seznamu :cisla
se - vrací parametry spojené do seznamu
empy? - zjistí, zda je seznam prázdný, například if empty? :cisla [pr [prazdny]]
first - vybere první prvek seznamu
last - vybere poslední prvek seznamu
butfirst - vynechá první prvek seznamu
butlast - vynechá poslední prvek seznamu


Některé matematické operace

Pro řešení následující úlohy budeme potřebovat ještě další příkazy pro celočíselné dělení:
div :a :b - celočíselné dělení (kolikrát se druhý parametr vejde do prvního), například: div 14 5 , výsledek je 2
mod :a :b - zbytek po celočíselném dělení, například: mod 14 5 , výsledek je 4

Další matematické příkazy pro práci s desetinnými čísly jsou:
round - zaokrouhlí desetinné číslo na celé
int - odřízne z čísla jeho desetinnou část

Boghayský Bukaj

Práci se seznamy vyzkoušíme na částečném řešení jedné ze soutěžních úloh okresního kola soutěže v programování z roku 2010 (byla zadaná také již někdy dříve).
Boghayský Bukaj
V království Boghay mají měnovou jednotku jeden Bukaj boghayský. Každý rok tam ale probíhá měnová reforma. Základní jednotka 1 Bukaj vždy zůstává, ale vyěěí bankovky již dávno nejsou násobky dvou, pěti či deseti, jak bývž ve světě zvykem, ale jsou to libovolné celočíselné násobky Bukaje, pokaždé jiné. Např. vloni byly v oběhu tyto bankovky: 1 BB, 4 BB, 13 BB, 74 BB, 301 BB a 302 BB. Napište program, který bude pomáhat královskému pokladnímu vyplácet libovolný obnos. Program po zadání hodnot jednotlivých bankovek, jejich množství v královské pokladně a velikosti vyplácené částky zjistí, jakým nejmenším počtem bankovek lze uvedenou částku vyplatiti (pokud to vůbec jde), a vypíše hodnoty a počty vyplácených bankovek. Např. pro výše uvedené hodnoty bankovek při dostatečné zásobě v královské pokladně program doporučí vyplatit částku 379 BB bankovkami 301 BB (1 ks), 74 BB (1 ks) a 4 BB (1 ks).


Prostředí programu se bude skládat z několika textových polí a tlačítek - viz obrázek:

Na začátku (při každé měnové reformě :-) ) se použije tlačítko Nová měna, které spustí proceduru start:
to start
make"bankovky []
text3'setvalue " text8'setvalue "
text1'setvalue 0
text2'setvalue 0
end
Procedura do proměnné bankovky uloží prázdný seznam (vyprázdní seznam bankovek), vyprázdní textová pole text3 a text8, do kterých se vypisuje seznam bankovek a počty bankovek (na obrázku žluté a červené), do textových polí text1 a text2 pro vkládání bankovek a částky zapíše nulu (na obrázku světle modrá pole). U těchto dvou polí, do kterých chceme vkládat text, nezapomeňte ve vlastnostech zaškrtnout Úpravy a Zůstávají úpravy.

Tlačítko Vlož bankovku obsahuje příkazy, které přidají vložené číslo do seznamu bankovek (pro zjednodušení vkládáme bankovky od největší po nejmenší) a vytiskne ho do textového pole text3:
make "bankovky se :bankovky text1 printtotextbox "text3 ( print text1 [BB] )
Do proměnné bankovky se uloží spojený původní seznam, uložený v této proměnné, s textem v poli text1 (nekontrolujeme, co je v poli text1 zapsané, což by profesionální program dělat měl, aby místo čísel nebyly vložené jiné znaky). Příkazem printtotextbox určíme, do kterého pole se bude tisknout příkazem pr (print), protože polí pro tisk máme v programu více.

Poslední proceduru vyplat spustí tlačítko Potvrď částku po vožení částky, kterou chceme pomocí zadaných bankovek vyplatit. Procedura obsahuje komentáře, to jsou texty za středníkem, které Imagine ignoruje:
to vyplat
text8'setvalue "
make"castka text2
;do proměnné :pocet uložím délku seznamu :bankovky (počet bankovek)
make"pocet count :bankovky
;vytvořím pomocný seznam :pomban, protože v průběhu procedury ho budu zkracovat
make"pomban :bankovky
repeat :pocet
;příkaz div je celočíselné dělení (kolik bude potřeba příslušných bankovek)
;vydělím částku první bankovkou a počet bankovek uložím do proměnné :kusu
[make"kusu div :castka first :pomban
;printtotextbox určuje kam se bude tiknout příkazem pr (print), když se tiskne víc věcí, je celý příkaz pr v kulaté závorce
printtotextbox "text8 (pr [bankovka: ] first :pomban [BB, kusu: ] :kusu)
;příkaz mod určuje zbytek po dělení (kolik zbylo po vyplacení první bankovky)
make"castka mod :castka first :pomban
;pomocný seznam :pomban zkrátíme o první prvek
make"pomban butfirst :pomban]
(pr [zbylo nevyplaceno: ] :castka)
end


Superciferný součet

Práci s řetězci můžeme využít například pro řešení jedné z úloh krajského kola programování z roku 2010 pro výpočet tzv. superciferného součtu, kdy se počítá ciferný součet tak dlouho, dokud není menší než 10. Například číslo 1234567 má ciferný součet 1+2+3+4+5+6+7 = 28, ten je větší než 9, proto se počítá dál ciferný součet čísla 28, to je 2+8 = 10, i tento součet je větší než 9, počítá se tedy další, teprve ciferný součet 1+0 = 1 je menší než 9 a je výsledným superciferným součtem.

Prostředí programu bude tentokrát obsahovat jen jedno textové pole text1 pro zápis čísla (řetězce), tlačítko pro spuštění procedury start a druhé textové pole text3 pro výpis výsledku (samozřejmě je vhodné doplnit další popisy). Startovací procedura by mohla vypadat takto:
to start
text3'setvalue "
;vyprázdníme pole pro výpis výsledku
make"cislo text1
; do proměnné :cislo vložíme zadané číslo
make"cif_soucet 0
;proměnná :cif_soucet bude obsahovat průběžné ciferné součty
spocti
printtotextbox "text3 pr :cif_soucet
end
V proceduře start se připraví textová pole a proměnné a zavolá se procedura spocti, která vypočte výsledný součet, ten se nakonec tiskne do pole text3.
Procedura spocti počítá celkový ciferný součet třeba pomocí rekurze:
to spocti
soucet
ifelse :cif_soucet>9 [make"cislo :cif_soucet make"cif_soucet 0 soucet] [stop]
spocti
end
Procedura spocti nejprve volá proceduru soucet, která vypočte ciferný součet proměnné cislo (první její hodnota byla zadaná v poli text1). Pokud vypočtený ciferný součet bude větší než 9, uloží se do proměnné cislo, vynuluje se a znovu se volá procedura spocti, pokud už je ciferný součet menší než 9, procedura skončí a v proměnné cif_soucet je výsledný superciferný součet.
Kdo vydržel až sem, dočkal se jádra problému, který řeší procedura soucet, ta vypočte ciferný součet proměnné cislo:
to soucet
if empty? :cislo [stop]
;je-li cislo prázdné, procedura se zastaví
make"cif_soucet :cif_soucet+last :cislo
;proměnná :cif_soucet se zvětší o poslední číslici proměnné :cislo
make"cislo butlast :cislo
;do proměnné :cislo se uloží tato proměnná bez poslední číslice
soucet
;a pořád dokola:-)
end
Princip je snad jasný z komentářů procedury, jenom chci upozornit, že ve většině programovacích jazyků musí být určeno, co budeme do proměnné ukládat, například jestli číslo nebo řetězec (slova, písmena) - Imagine nás těchto starostí zbavuje, jak je vidět z této procedury, kde s vloženým číslem pracujeme jako s řetězcem znaků (klidně k číslu přičteme poslední písmeno). Navíc existují různá omezení pro čísla, v Imagine bychom mohli použít maximálně deseticiferné, v jiných jazycích existují různé typy proměnných pro různě velká čísla. U tohoto řešení pomocí řetězce jsem úspěšně vyzkoušel 300 ciferné číslo, možná se najde odvážlivec, který zjistí, kolik maximálně znaků lze pro řetězec v Imagine použít:-)

Projekt ulož pod názvem lekce21.imp !

Úkol:

Naprogramujte tah Sportky - čili nalezení šesti různých náhodných čísel od 1 do 49.


Úkol pro experty:

Uvedené řešení zadané "měnové" úlohy je jen částečné, pokud zkusíte hodnoty uvedené v zadání, nedostanete nejmenší počet bankovek. Zkuste proceduru vyplat o něco vylepšit.